【新機能】BigQuery で GROUP BY と SELECT DISTINCT が ARRAY と STRUCT にも使えるようになりました
Google Cloud データエンジニアのはんざわです。
2024年8月29日のアップデートにより、ARRAY
型と STRUCT
型にも GROUP BY
と SELECT DISTINCT
が使えるようになりました。
You can now use the
GROUP BY
clause and theSELECT DISTINCT
clause with theARRAY
andSTRUCT
data types. This feature is in Preview.
本ブログでは、さっそくその使い方を紹介したいと思います。
このアップデートの何が嬉しいの?
GROUP BY
と SELECT DISTINCT
のそれぞれのケースで、従来のクエリとどのように変わるのかを見てみましょう。
GROUP BY
これまでは、ARRAY
型に集約関数を使用したい場合、一度 ARRAY
型を文字列に変換してから集約関数を実行する必要がありました。
今後はそのような前処理をする必要がなくなり、よりシンプルなクエリで集約関数を使用することが可能になりました。
WITH sample AS (
SELECT ['A', 'B', 'C'] AS arr, 3 AS cnt
UNION ALL
SELECT ['D', 'E', 'F'] AS arr, 2 AS cnt
UNION ALL
SELECT ['A', 'B', 'C'] AS arr, 5 AS cnt
)
SELECT
ARRAY_TO_STRING(arr, ','),
SUM(cnt) AS sum_cnt
FROM
sample
GROUP BY arr
WITH sample AS (
SELECT ['A', 'B', 'C'] AS arr, 3 AS cnt
UNION ALL
SELECT ['D', 'E', 'F'] AS arr, 2 AS cnt
UNION ALL
SELECT ['A', 'B', 'C'] AS arr, 5 AS cnt
)
SELECT
arr,
SUM(cnt) AS sum_cnt
FROM
sample
GROUP BY arr
また、 STRUCT
型も同様に簡潔なクエリで集約関数を実行することができるようになりました。
従来は、STRUCT
型のフィールドから一意になるようなキーの組み合わせを抽出して集約関数を実行する必要がありましたが、今後は不要になると思われます。
WITH sample AS (
SELECT STRUCT(1 AS id, 'apple' AS name) AS f_struct, 3 AS cnt
UNION ALL
SELECT STRUCT(2 AS id, 'banana' AS name) AS f_struct, 2 AS cnt
UNION ALL
SELECT STRUCT(1 AS id, 'apple' AS name) AS f_struct, 5 AS cnt
)
SELECT
f_struct.id,
SUM(cnt) AS sum_cnt
FROM
sample
GROUP BY f_struct.id
WITH sample AS (
SELECT STRUCT(1 AS id, 'apple' AS name) AS f_struct, 3 AS cnt
UNION ALL
SELECT STRUCT(2 AS id, 'banana' AS name) AS f_struct, 2 AS cnt
UNION ALL
SELECT STRUCT(1 AS id, 'apple' AS name) AS f_struct, 5 AS cnt
)
SELECT
f_struct,
SUM(cnt) AS sum_cnt
FROM
sample
GROUP BY f_struct
SELECT DISTINCT
これまでもテーブルの一意判定を行う際に SELECT DISTINCT
を使用していましたが、ARRAY
型や STRUCT
型のデータが含まれていると使用することができませんでした。
その対処法として、主キーと QUALIFY
でユニーク化するなど、別のアプローチを取る必要がありました。
しかし、DISTINCT
が ARRAY
型と STRUCT
型にも対応したことで、今までよりもシンプルなクエリでテーブルをユニーク化することが可能になりました。
WITH sample AS (
SELECT 1 AS id, [1, 2, 3] AS arr
UNION ALL
SELECT 2 AS id, [4, 5, 6] AS arr
UNION ALL
SELECT 1 AS id, [1, 2, 3] AS arr
)
SELECT
*
FROM
sample
QUALIFY ROW_NUMBER() OVER(PARTITION BY id) = 1
WITH sample AS (
SELECT 1 AS id, [1, 2, 3] AS arr
UNION ALL
SELECT 2 AS id, [4, 5, 6] AS arr
UNION ALL
SELECT 1 AS id, [1, 2, 3] AS arr
)
SELECT
DISTINCT *
FROM
sample
関連の機能も検証してみる
今回のアップデートに関連して、いくつか気になる点があったため、検証してみました。
検証項目は以下の通りです。
EXCEPT DISTINCT
は使えるのかJSON
型でも使えるのか
1. EXCEPT DISTINCT は使えるのか
結論として、EXCEPT DISTINCT
はまだ使えないようです。。。
SELECT [1, 2, 3] AS arr, 1 AS cnt
EXCEPT DISTINCT
SELECT [1, 2, 3] AS arr, 1 AS cnt
> Type ARRAY is not supported in INTERSECT DISTINCT or EXCEPT DISTINCT operation
以下のブログでも紹介されているように、EXCEPT DISTINCT
を使用することで複数のテーブルの一致判定を行うことができますが、この方法には問題があります。
しかし、この方法には問題があり、ARRAY
や STRUCT
型には対応していないため、別のアプローチを取る必要がありました。
EXCEPT DISTINCT
を 2 つのテーブルで双方向に行い、対称差を求めます。対称差が存在しなければ、一致していると見なすことができます。
しかし、
Groupable
でない型ARRAY
,STRUCT
,GEOGRAPHY
には対応できない問題があります
ARRAY
や STRUCT
型には対応していないため、別のアプローチを取る必要がありましたが、今後のアップデートで EXCEPT DISTINCT
がこれらの型にも対応することを期待しています。
2. JSON でも使えるのか
残念ながら、こちらも使えないようです。。。
WITH sample AS (
SELECT JSON '{"key": "apple"}' AS json_o
UNION ALL
SELECT JSON '{"key": "apple"}' AS json_o
)
SELECT
DISTINCT json_o
FROM
sample
> Column json_o of type JSON cannot be used in SELECT DISTINCT
筆者は、STRUCT
型があまり好きではないため、代わりに JSON
型を採用しています。
JSON
型のテーブルも、STRUCT
型と同様に主キーと QUALIFY
を使ってユニーク化することが多いので、JSON
型でも SELECT DISTINCT
が実行できるようになると嬉しいなーと思いました。
(とはいえ、JSON
型はキーの順序が一定でないため、難しいかもしれませんが...)
まとめ
本ブログでは、新たにプレビュー機能となった ARRAY
型と STRUCT
型に対する GROUP BY
と SELECT DISTINCT
の使用方法を試してみました。
最近プレビューに追加された JSON_KEYS
の機能もそうですが、地味ながらも便利なアップデートが続いている印象です。
このような痒い所に手が届く機能がどんどん追加されることは、筆者として非常に嬉しい限りです。
今後のアップデートにも期待が高まります。